package biback.domain.customer

import biback.domain._
import biback.domain.cash.{BoxCashWithdraw, TellerBoxEntity}
import biback.domain.common.TrnContext
import biback.domain.product.BaseProduct.{CurrentDeposit1st, CurrentDeposit2nd}
import biback.domain.product.{BaseProduct, ProductAlgebra, ProductParam}
import biback.utils.RegistryAlgebra
import cats.Monad

class AccountWithdrawService[F[_] : Monad]
(
  algebra: RegistryAlgebra[F] with PersonalAlgebra[F] with ProductAlgebra[F]
) extends DomainService[F, CashWithdrawRequest, Unit] {

  import algebra._

  def run(ctx: TrnContext, rq: CashWithdrawRequest): ErrOrNoneF = {
    for {
      s <- customer.foundCustomerProduct(rq.acctId, rq.subAcctNo)
      a <- product.foundParam(s.product.base)
      _ <- orF(withdrawPreCheck(ctx, rq, s.product.base, a))
      t <- registry.refFor[TellerBoxEntity](ctx.oper.tlrNo.get.toString)
      _ <- t.ask(BoxCashWithdraw(ctx, rq.trnAmt.value, s.product.ccy))
      p <- registry.refFor[PersonalEntity](s.cNo.value)
      e <- p.ask(CashWithdraw(ctx, rq.acctId, rq.subAcctNo, rq.trnAmt.value, a)) // TODO: 支持TCC
    } yield e
  }

  // 部分支取
  def withdrawPartial(): ErrOrNoneF = ???

  // 取息
  def withdrawInterest(): ErrOrNoneF = ???


  def withdrawPreCheck(ctx: TrnContext, o: CashWithdrawRequest, product: BaseProduct, param: ProductParam): ErrOrNone = {
    import ProductParam._
    val inputs = new TrnChannelSetter with InvokerSetter {
      val trnChannel = ctx.channel
      val invoker = ctx.oper.tlrNo
    }
    product match {
      case CurrentDeposit1st =>
        CurrentDeposit1st.withdrawPre(param, inputs)
      case CurrentDeposit2nd =>
        CurrentDeposit2nd.withdrawPre(param, inputs)
    }
  }
}

case class CashWithdrawRequest
(
  acctId: AccountId,
  subAcctNo: SubAccountNo,
  trnAmt: NnDec
)
